﻿using System;
using System.Diagnostics.Contracts;

namespace ReactiveLang
{
    [ContractClass(typeof(IExpressionParentContract<>))]
    public interface IExpressionParent<in T> : INodeParent
    {
        void OnValue(T value);
    }

    #region Contract for IExpressionParent<T>

    [ContractClassFor(typeof(IExpressionParent<>))]
    abstract class IExpressionParentContract<T> : IExpressionParent<T>
    {
        public void OnException(Exception ex)
        {
        }

        public void OnValue(T value)
        {
        }
    }

    #endregion

    public class ExpressionParent
    {
        class AnonymousExpressionParent<T> : IExpressionParent<T>
        {
            internal Action<T> _onValue;
            public void OnValue(T value)
            {
                _onValue(value);
            }

            internal Action<Exception> _onException;
            public void OnException(Exception ex)
            {
                _onException(ex);
            }
        }
        public static IExpressionParent<T> Create<T>(Action<T> onValue, Action<Exception> onException = null)
        {
            Contract.Requires<ArgumentNullException>(onValue != null, "value");
            Contract.Ensures(Contract.Result<IExpressionParent<T>>() != null);
            if (onException == null)
                onException = ex => { throw ex; };
            return new AnonymousExpressionParent<T> { _onValue = onValue, _onException = onException };
        }
    }
}